"""
流媒体质量控制模块
"""

import asyncio
import time
from typing import Dict, List, Any, Optional, Tuple
from dataclasses import dataclass, field
from enum import Enum
import logging
import numpy as np


class QualityLevel(Enum):
    """质量等级"""
    AUTO = "auto"
    LOW = "low"
    MEDIUM = "medium"
    HIGH = "high"
    ULTRA = "ultra"


class AdaptationStrategy(Enum):
    """自适应策略"""
    CONSERVATIVE = "conservative"  # 保守策略，优先稳定性
    BALANCED = "balanced"          # 平衡策略
    AGGRESSIVE = "aggressive"      # 激进策略，优先质量


@dataclass
class QualityMetrics:
    """质量指标"""
    bandwidth_kbps: float = 0.0
    latency_ms: float = 0.0
    packet_loss_rate: float = 0.0
    jitter_ms: float = 0.0
    buffer_health: float = 0.5
    cpu_usage: float = 0.0
    memory_usage: float = 0.0
    timestamp: float = field(default_factory=time.time)


@dataclass
class QualityConfig:
    """质量配置"""
    strategy: AdaptationStrategy = AdaptationStrategy.BALANCED
    
    # 质量等级定义
    low_quality: Dict[str, Any] = field(default_factory=lambda: {
        "bitrate": 64,
        "sample_rate": 16000,
        "channels": 1,
        "format": "mp3",
        "compression": 3
    })
    
    medium_quality: Dict[str, Any] = field(default_factory=lambda: {
        "bitrate": 128,
        "sample_rate": 22050,
        "channels": 1,
        "format": "mp3",
        "compression": 5
    })
    
    high_quality: Dict[str, Any] = field(default_factory=lambda: {
        "bitrate": 256,
        "sample_rate": 44100,
        "channels": 2,
        "format": "mp3",
        "compression": 7
    })
    
    ultra_quality: Dict[str, Any] = field(default_factory=lambda: {
        "bitrate": 320,
        "sample_rate": 48000,
        "channels": 2,
        "format": "flac",
        "compression": 8
    })
    
    # 自适应参数
    adaptation_interval: float = 2.0  # 自适应检查间隔(秒)
    metrics_window: int = 10       # 指标窗口大小
    stability_threshold: float = 0.7  # 稳定性阈值
    bandwidth_margin: float = 0.2   # 带宽余量
    latency_threshold: float = 200.0  # 延迟阈值(ms)
    packet_loss_threshold: float = 0.05  # 丢包率阈值


class QualityController:
    """质量控制器"""
    
    def __init__(self, config: QualityConfig):
        self.config = config
        self._current_level = QualityLevel.MEDIUM
        self._target_level = QualityLevel.MEDIUM
        
        # 指标收集
        self._metrics_history: List[QualityMetrics] = []
        self._quality_scores: List[float] = []
        
        # 控制状态
        self._adaptation_enabled = True
        self._last_adaptation = 0.0
        self._adaptation_count = 0
        
        # 回调函数
        self._quality_change_callbacks: List[Callable[[QualityLevel, QualityLevel, str], None]] = []
        
        # 统计信息
        self._stats = {
            "total_adaptations": 0,
            "upgrades": 0,
            "downgrades": 0,
            "quality_changes": [],
            "average_score": 0.0
        }
    
    def add_metrics(self, metrics: QualityMetrics):
        """添加质量指标"""
        self._metrics_history.append(metrics)
        
        # 限制历史记录大小
        if len(self._metrics_history) > self.config.metrics_window:
            self._metrics_history.pop(0)
        
        # 计算质量分数
        score = self._calculate_quality_score(metrics)
        self._quality_scores.append(score)
        
        if len(self._quality_scores) > self.config.metrics_window:
            self._quality_scores.pop(0)
    
    def _calculate_quality_score(self, metrics: QualityMetrics) -> float:
        """计算质量分数 (0.0-1.0)"""
        score = 0.0
        
        # 带宽分数 (越高越好)
        if metrics.bandwidth_kbps > 0:
            # 基于当前质量等级计算期望带宽
            expected_bandwidth = self._get_expected_bandwidth(self._current_level)
            bandwidth_score = min(1.0, metrics.bandwidth_kbps / (expected_bandwidth * (1 + self.config.bandwidth_margin)))
            score += bandwidth_score * 0.3
        else:
            score += 0.3
        
        # 延迟分数 (越低越好)
        if metrics.latency_ms > 0:
            latency_score = max(0.0, 1.0 - (metrics.latency_ms / self.config.latency_threshold))
            score += latency_score * 0.25
        else:
            score += 0.25
        
        # 丢包率分数 (越低越好)
        if metrics.packet_loss_rate < self.config.packet_loss_threshold:
            packet_loss_score = 1.0 - (metrics.packet_loss_rate / self.config.packet_loss_threshold)
        else:
            packet_loss_score = 0.0
        score += packet_loss_score * 0.2
        
        # 缓冲区健康度
        buffer_score = metrics.buffer_health
        score += buffer_score * 0.15
        
        # 系统资源使用率
        system_score = max(0.0, 1.0 - (metrics.cpu_usage + metrics.memory_usage) / 200.0)
        score += system_score * 0.1
        
        return min(1.0, score)
    
    def _get_expected_bandwidth(self, level: QualityLevel) -> float:
        """获取期望带宽"""
        bandwidth_map = {
            QualityLevel.LOW: 64,
            QualityLevel.MEDIUM: 128,
            QualityLevel.HIGH: 256,
            QualityLevel.ULTRA: 320
        }
        return bandwidth_map.get(level, 128)
    
    async def start_adaptation(self):
        """启动自适应质量控制"""
        self._adaptation_enabled = True
        
        while self._adaptation_enabled:
            try:
                await self._adapt_quality()
                await asyncio.sleep(self.config.adaptation_interval)
            except Exception as e:
                logging.error(f"质量自适应错误: {e}")
                await asyncio.sleep(self.config.adaptation_interval)
    
    async def _adapt_quality(self):
        """自适应质量调整"""
        if not self._metrics_history:
            return
        
        current_time = time.time()
        
        # 限制调整频率
        if current_time - self._last_adaptation < self.config.adaptation_interval:
            return
        
        # 计算平均质量分数
        avg_score = np.mean(self._quality_scores)
        self._stats["average_score"] = avg_score
        
        # 根据策略决定质量调整
        new_level = self._determine_target_level(avg_score)
        
        if new_level != self._current_level:
            await self._change_quality(new_level, f"Adaptive adjustment (score: {avg_score:.3f})")
    
    def _determine_target_level(self, avg_score: float) -> QualityLevel:
        """确定目标质量等级"""
        if not self._adaptation_enabled:
            return self._current_level
        
        current_index = self._get_quality_index(self._current_level)
        
        if self.config.strategy == AdaptationStrategy.CONSERVATIVE:
            # 保守策略：需要很高的分数才升级，很低的分数才降级
            if avg_score > 0.9 and current_index < len(self._get_all_levels()) - 1:
                return self._get_all_levels()[current_index + 1]
            elif avg_score < 0.3 and current_index > 0:
                return self._get_all_levels()[current_index - 1]
        
        elif self.config.strategy == AdaptationStrategy.AGGRESSIVE:
            # 激进策略：积极追求高质量
            if avg_score > 0.6 and current_index < len(self._get_all_levels()) - 1:
                return self._get_all_levels()[current_index + 1]
            elif avg_score < 0.4 and current_index > 0:
                return self._get_all_levels()[current_index - 1]
        
        else:  # BALANCED
            # 平衡策略：适中的阈值
            if avg_score > 0.8 and current_index < len(self._get_all_levels()) - 1:
                return self._get_all_levels()[current_index + 1]
            elif avg_score < 0.5 and current_index > 0:
                return self._get_all_levels()[current_index - 1]
        
        return self._current_level
    
    def _get_all_levels(self) -> List[QualityLevel]:
        """获取所有质量等级"""
        return [QualityLevel.LOW, QualityLevel.MEDIUM, QualityLevel.HIGH, QualityLevel.ULTRA]
    
    def _get_quality_index(self, level: QualityLevel) -> int:
        """获取质量等级索引"""
        levels = self._get_all_levels()
        try:
            return levels.index(level)
        except ValueError:
            return 1  # 默认MEDIUM
    
    async def _change_quality(self, new_level: QualityLevel, reason: str):
        """改变质量等级"""
        old_level = self._current_level
        self._current_level = new_level
        self._target_level = new_level
        self._last_adaptation = time.time()
        self._adaptation_count += 1
        
        # 更新统计
        self._stats["total_adaptations"] += 1
        self._stats["quality_changes"].append({
            "timestamp": self._last_adaptation,
            "old_level": old_level.value,
            "new_level": new_level.value,
            "reason": reason
        })
        
        # 统计升降级
        old_index = self._get_quality_index(old_level)
        new_index = self._get_quality_index(new_level)
        if new_index > old_index:
            self._stats["upgrades"] += 1
        elif new_index < old_index:
            self._stats["downgrades"] += 1
        
        # 通知回调
        for callback in self._quality_change_callbacks:
            try:
                if asyncio.iscoroutinefunction(callback):
                    await callback(old_level, new_level, reason)
                else:
                    callback(old_level, new_level, reason)
            except Exception as e:
                logging.error(f"质量变化回调错误: {e}")
        
        logging.info(f"质量等级变化: {old_level.value} -> {new_level.value}, 原因: {reason}")
    
    def set_quality_level(self, level: QualityLevel, reason: str = "Manual"):
        """手动设置质量等级"""
        if level != self._current_level:
            asyncio.create_task(self._change_quality(level, reason))
    
    def set_adaptation_strategy(self, strategy: AdaptationStrategy):
        """设置自适应策略"""
        self.config.strategy = strategy
        logging.info(f"自适应策略设置为: {strategy.value}")
    
    def enable_adaptation(self):
        """启用自适应"""
        self._adaptation_enabled = True
    
    def disable_adaptation(self):
        """禁用自适应"""
        self._adaptation_enabled = False
    
    def add_quality_change_callback(self, callback: Callable[[QualityLevel, QualityLevel, str], None]):
        """添加质量变化回调"""
        self._quality_change_callbacks.append(callback)
    
    def get_current_quality_config(self) -> Dict[str, Any]:
        """获取当前质量配置"""
        config_map = {
            QualityLevel.LOW: self.config.low_quality,
            QualityLevel.MEDIUM: self.config.medium_quality,
            QualityLevel.HIGH: self.config.high_quality,
            QualityLevel.ULTRA: self.config.ultra_quality
        }
        return config_map.get(self._current_level, self.config.medium_quality)
    
    def get_current_level(self) -> QualityLevel:
        """获取当前质量等级"""
        return self._current_level
    
    def get_metrics_summary(self) -> Dict[str, Any]:
        """获取指标摘要"""
        if not self._metrics_history:
            return {}
        
        # 计算各项指标的统计
        bandwidths = [m.bandwidth_kbps for m in self._metrics_history if m.bandwidth_kbps > 0]
        latencies = [m.latency_ms for m in self._metrics_history if m.latency_ms > 0]
        packet_losses = [m.packet_loss_rate for m in self._metrics_history]
        buffer_healths = [m.buffer_health for m in self._metrics_history]
        
        summary = {
            "current_level": self._current_level.value,
            "current_config": self.get_current_quality_config(),
            "metrics_count": len(self._metrics_history),
            "average_score": np.mean(self._quality_scores) if self._quality_scores else 0.0
        }
        
        if bandwidths:
            summary["bandwidth"] = {
                "current": bandwidths[-1] if bandwidths else 0,
                "average": np.mean(bandwidths),
                "min": np.min(bandwidths),
                "max": np.max(bandwidths)
            }
        
        if latencies:
            summary["latency"] = {
                "current": latencies[-1] if latencies else 0,
                "average": np.mean(latencies),
                "min": np.min(latencies),
                "max": np.max(latencies)
            }
        
        if packet_losses:
            summary["packet_loss"] = {
                "current": packet_losses[-1] if packet_losses else 0,
                "average": np.mean(packet_losses),
                "min": np.min(packet_losses),
                "max": np.max(packet_losses)
            }
        
        if buffer_healths:
            summary["buffer_health"] = {
                "current": buffer_healths[-1] if buffer_healths else 0,
                "average": np.mean(buffer_healths),
                "min": np.min(buffer_healths),
                "max": np.max(buffer_healths)
            }
        
        return summary
    
    def get_stats(self) -> Dict[str, Any]:
        """获取统计信息"""
        return {
            **self._stats,
            "adaptation_enabled": self._adaptation_enabled,
            "current_level": self._current_level.value,
            "strategy": self.config.strategy.value,
            "adaptation_count": self._adaptation_count
        }
    
    def reset_stats(self):
        """重置统计信息"""
        self._stats = {
            "total_adaptations": 0,
            "upgrades": 0,
            "downgrades": 0,
            "quality_changes": [],
            "average_score": 0.0
        }
        self._adaptation_count = 0
        self._metrics_history.clear()
        self._quality_scores.clear()
    
    def stop_adaptation(self):
        """停止自适应"""
        self._adaptation_enabled = False


class NetworkMonitor:
    """网络监控器"""
    
    def __init__(self):
        self._packet_times: List[float] = []
        self._packet_sizes: List[int] = []
        self._lost_packets = 0
        self._total_packets = 0
        self._start_time = time.time()
    
    def record_packet(self, size: int, lost: bool = False):
        """记录数据包"""
        current_time = time.time()
        
        if not lost:
            self._packet_times.append(current_time)
            self._packet_sizes.append(size)
            self._total_packets += 1
        else:
            self._lost_packets += 1
            self._total_packets += 1
        
        # 限制数据量
        max_samples = 100
        if len(self._packet_times) > max_samples:
            self._packet_times = self._packet_times[-max_samples:]
            self._packet_sizes = self._packet_sizes[-max_samples:]
    
    def get_network_metrics(self) -> QualityMetrics:
        """获取网络指标"""
        # 计算带宽 (kbps)
        bandwidth = 0.0
        if len(self._packet_times) > 1 and len(self._packet_sizes) > 1:
            time_window = self._packet_times[-1] - self._packet_times[0]
            if time_window > 0:
                total_bytes = sum(self._packet_sizes)
                bandwidth = (total_bytes * 8) / (time_window * 1000)  # kbps
        
        # 计算延迟和抖动
        latency = 0.0
        jitter = 0.0
        if len(self._packet_times) > 1:
            intervals = np.diff(self._packet_times)
            latency = np.mean(intervals) * 1000  # ms
            jitter = np.std(intervals) * 1000  # ms
        
        # 计算丢包率
        packet_loss = self._lost_packets / max(self._total_packets, 1)
        
        return QualityMetrics(
            bandwidth_kbps=bandwidth,
            latency_ms=latency,
            packet_loss_rate=packet_loss,
            jitter_ms=jitter,
            timestamp=time.time()
        )
    
    def reset(self):
        """重置监控器"""
        self._packet_times.clear()
        self._packet_sizes.clear()
        self._lost_packets = 0
        self._total_packets = 0
        self._start_time = time.time()
